home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / gdb / gdb_18s.zoo / m68k-pinsn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-25  |  19.7 KB  |  858 lines

  1. /* Print m68k instructions for GDB, the GNU debugger.
  2.    Copyright (C) 1986, 1987 Free Software Foundation, Inc.
  3.  
  4. GDB is distributed in the hope that it will be useful, but WITHOUT ANY
  5. WARRANTY.  No author or distributor accepts responsibility to anyone
  6. for the consequences of using it or for whether it serves any
  7. particular purpose or works at all, unless he says so in writing.
  8. Refer to the GDB General Public License for full details.
  9.  
  10. Everyone is granted permission to copy, modify and redistribute GDB,
  11. but only under the conditions described in the GDB General Public
  12. License.  A copy of this license is supposed to have been given to you
  13. along with GDB so you can know your rights and responsibilities.  It
  14. should be in a file named COPYING.  Among other things, the copyright
  15. notice and this notice must be preserved on all copies.
  16.  
  17. In other words, go ahead and share GDB, but don't try to stop
  18. anyone else from sharing it farther.  Help stamp out software hoarding!
  19. */
  20.  
  21. #include <stdio.h>
  22.  
  23. #include "defs.h"
  24. #include "param.h"
  25. #include "symtab.h"
  26. #include "m68k-opcode.h"
  27.  
  28. /* 68k instructions are never longer than this many bytes.  */
  29. #define MAXLEN 22
  30.  
  31. /* Number of elements in the opcode table.  */
  32. #define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
  33.  
  34. extern char *reg_names[];
  35. char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
  36.              "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
  37.  
  38. static unsigned char *print_insn_arg ();
  39. static unsigned char *print_indexed ();
  40. static void print_base ();
  41. static int fetch_arg ();
  42.  
  43. #define NEXTBYTE(p)  (p += 2, ((char *)p)[-1])
  44.  
  45. #define NEXTWORD(p)  \
  46.   (p += 2, ((((char *)p)[-2]) << 8) + p[-1])
  47.  
  48. #define NEXTLONG(p)  \
  49.   (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
  50.  
  51. #define NEXTSINGLE(p) \
  52.   (p += 4, *((float *)(p - 4)))
  53.  
  54. #define NEXTDOUBLE(p) \
  55.   (p += 8, *((double *)(p - 8)))
  56.  
  57. #define NEXTEXTEND(p) \
  58.   (p += 12, 0.0)    /* Need a function to convert from extended to double
  59.                precision... */
  60.  
  61. #define NEXTPACKED(p) \
  62.   (p += 12, 0.0)    /* Need a function to convert from packed to double
  63.                precision.   Actually, it's easier to print a
  64.                packed number than a double anyway, so maybe
  65.                there should be a special case to handle this... */
  66.  
  67. /* Print the m68k instruction at address MEMADDR in debugged memory,
  68.    on STREAM.  Returns length of the instruction, in bytes.  */
  69.  
  70. int
  71. print_insn (memaddr, stream)
  72.      CORE_ADDR memaddr;
  73.      FILE *stream;
  74. {
  75.   unsigned char buffer[MAXLEN];
  76.   register int i;
  77.   register unsigned char *p;
  78.   register char *d;
  79.   register int bestmask;
  80.   int best;
  81.  
  82.   read_memory (memaddr, buffer, MAXLEN);
  83.  
  84.   bestmask = 0;
  85.   best = -1;
  86.   for (i = 0; i < NOPCODES; i++)
  87.     {
  88.       register unsigned int opcode = m68k_opcodes[i].opcode;
  89.       register unsigned int match = m68k_opcodes[i].match;
  90.       if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
  91.       && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
  92.       && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
  93.       && ((0xff & buffer[3] & match) == (0xff & opcode)))
  94.     {
  95.       /* Don't use for printout the variants of divul and divsl
  96.          that have the same register number in two places.
  97.          The more general variants will match instead.  */
  98.       for (d = m68k_opcodes[i].args; *d; d += 2)
  99.         if (d[1] == 'D')
  100.           break;
  101.  
  102.       /* Don't use for printout the variants of most floating
  103.          point coprocessor instructions which use the same
  104.          register number in two places, as above. */
  105.       if (*d == 0)
  106.         for (d = m68k_opcodes[i].args; *d; d += 2)
  107.           if (d[1] == 't')
  108.         break;
  109.  
  110.       if (*d == 0 && match > bestmask)
  111.         {
  112.           best = i;
  113.           bestmask = match;
  114.         }
  115.     }
  116.     }
  117.  
  118.   /* Handle undefined instructions.  */
  119.   if (best < 0)
  120.     {
  121.       fprintf_filtered (stream, "0%o", (buffer[0] << 8) + buffer[1]);
  122.       return 2;
  123.     }
  124.  
  125.   fprintf_filtered (stream, "%s", m68k_opcodes[best].name);
  126.  
  127.   /* Point at first word of argument data,
  128.      and at descriptor for first argument.  */
  129.   p = buffer + 2;
  130.   
  131.   /* Why do this this way? -MelloN */
  132.   for (d = m68k_opcodes[best].args; *d; d += 2)
  133.     {
  134.       if (d[0] == '#')
  135.     {
  136.       if (d[1] == 'l' && p - buffer < 6)
  137.         p = buffer + 6;
  138.       else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
  139.         p = buffer + 4;
  140.     }
  141.       if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
  142.     p = buffer + 4;
  143.       if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
  144.     p = buffer + 6;
  145.       if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
  146.     p = buffer + 4;
  147.     }
  148.  
  149.   d = m68k_opcodes[best].args;
  150.  
  151.   if (*d)
  152.     fputc_filtered (' ', stream);
  153.  
  154.   while (*d)
  155.     {
  156.       p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream);
  157.       d += 2;
  158.       if (*d && *(d - 2) != 'I' && *d != 'k')
  159.     fprintf_filtered (stream, ",");
  160.     }
  161.   return p - buffer;
  162. }
  163.  
  164. static unsigned char *
  165. print_insn_arg (d, buffer, p, addr, stream)
  166.      char *d;
  167.      unsigned char *buffer;
  168.      register unsigned char *p;
  169.      CORE_ADDR addr;        /* PC for this arg to be relative to */
  170.      FILE *stream;
  171. {
  172.   register int val;
  173.   register int place = d[1];
  174.   int regno;
  175.   register char *regname;
  176.   register unsigned char *p1;
  177.   register double flval;
  178.   int flt_p;
  179.  
  180.   switch (*d)
  181.     {
  182.     case 'C':
  183.       fprintf_filtered (stream, "ccr");
  184.       break;
  185.  
  186.     case 'S':
  187.       fprintf_filtered (stream, "sr");
  188.       break;
  189.  
  190.     case 'U':
  191.       fprintf_filtered (stream, "usp");
  192.       break;
  193.  
  194.     case 'J':
  195.       {
  196.     static struct { char *name; int value; } names[]
  197.       = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
  198.          {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
  199.          {"msp", 0x803}, {"isp", 0x804}};
  200.  
  201.     val = fetch_arg (buffer, place, 12);
  202.     for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
  203.       if (names[regno].value == val)
  204.         {
  205.           fprintf_filtered (stream, names[regno].name);
  206.           break;
  207.         }
  208.     if (regno < 0)
  209.       fprintf_filtered (stream, "%d", val);
  210.       }
  211.       break;
  212.  
  213.     case 'Q':
  214.       val = fetch_arg (buffer, place, 3);
  215.       /* 0 means 8, except for the bkpt instruction... */
  216.       if (val == 0 && d[1] != 's')
  217.     val = 8;
  218.       fprintf_filtered (stream, "#%d", val);
  219.       break;
  220.  
  221.     case 'M':
  222.       val = fetch_arg (buffer, place, 8);
  223.       if (val & 0x80)
  224.     val = val - 0x100;
  225.       fprintf_filtered (stream, "#%d", val);
  226.       break;
  227.  
  228.     case 'T':
  229.       val = fetch_arg (buffer, place, 4);
  230.       fprintf_filtered (stream, "#%d", val);
  231.       break;
  232.  
  233.     case 'D':
  234.       fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
  235.       break;
  236.  
  237.     case 'A':
  238.       fprintf_filtered (stream, "%s",
  239.             reg_names[fetch_arg (buffer, place, 3) + 010]);
  240.       break;
  241.  
  242.     case 'R':
  243.       fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
  244.       break;
  245.  
  246.     case 'F':
  247.       fprintf_filtered (stream, "fp%d", fetch_arg (buffer, place, 3));
  248.       break;
  249.  
  250.     case 'O':
  251.       val = fetch_arg (buffer, place, 6);
  252.       if (val & 0x20)
  253.     fprintf_filtered (stream, "%s", reg_names [val & 7]);
  254.       else
  255.     fprintf_filtered (stream, "%d", val);
  256.       break;
  257.  
  258.     case '+':
  259.       fprintf_filtered (stream, "%s@+",
  260.             reg_names[fetch_arg (buffer, place, 3) + 8]);
  261.       break;
  262.  
  263.     case '-':
  264.       fprintf_filtered (stream, "%s@-",
  265.            reg_names[fetch_arg (buffer, place, 3) + 8]);
  266.       break;
  267.  
  268.     case 'k':
  269.       if (place == 'k')
  270.     fprintf_filtered (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
  271.       else if (place == 'C')
  272.     {
  273.       val = fetch_arg (buffer, place, 7);
  274.       if ( val > 63 )        /* This is a signed constant. */
  275.         val -= 128;
  276.       fprintf_filtered (stream, "{#%d}", val);
  277.     }
  278.       else
  279.     error ("Invalid arg format in opcode table: \"%c%c\".",
  280.            *d, place);
  281.       break;
  282.  
  283.     case '#':
  284.     case '^':
  285.       p1 = buffer + (*d == '#' ? 2 : 4);
  286.       if (place == 's')
  287.     val = fetch_arg (buffer, place, 4);
  288.       else if (place == 'C')
  289.     val = fetch_arg (buffer, place, 7);
  290.       else if (place == '8')
  291.     val = fetch_arg (buffer, place, 3);
  292.       else if (place == '3')
  293.     val = fetch_arg (buffer, place, 8);
  294.       else if (place == 'b')
  295.     val = NEXTBYTE (p1);
  296.       else if (place == 'w')
  297.     val = NEXTWORD (p1);
  298.       else if (place == 'l')
  299.     val = NEXTLONG (p1);
  300.       else
  301.     error ("Invalid arg format in opcode table: \"%c%c\".",
  302.            *d, place);
  303.       fprintf_filtered (stream, "#%d", val);
  304.       break;
  305.  
  306.     case 'B':
  307.       if (place == 'b')
  308.     val = NEXTBYTE (p);
  309.       else if (place == 'w')
  310.     val = NEXTWORD (p);
  311.       else if (place == 'l')
  312.     val = NEXTLONG (p);
  313.       else if (place == 'g')
  314.     {
  315.       val = ((char *)buffer)[1];
  316.       if (val == 0)
  317.         val = NEXTWORD (p);
  318.       else if (val == -1)
  319.         val = NEXTLONG (p);
  320.     }
  321.       else if (place == 'c')
  322.     {
  323.       if (buffer[1] & 0x40)        /* If bit six is one, long offset */
  324.         val = NEXTLONG (p);
  325.       else
  326.         val = NEXTWORD (p);
  327.     }
  328.       else
  329.     error ("Invalid arg format in opcode table: \"%c%c\".",
  330.            *d, place);
  331.  
  332.       print_address (addr + val, stream);
  333.       break;
  334.  
  335.     case 'd':
  336.       val = NEXTWORD (p);
  337.       fprintf_filtered (stream, "%s@(%d)",
  338.             reg_names[fetch_arg (buffer, place, 3)], val);
  339.       break;
  340.  
  341.     case 's':
  342.       fprintf_filtered (stream, "%s",
  343.             fpcr_names[fetch_arg (buffer, place, 3)]);
  344.       break;
  345.  
  346.     case 'I':
  347.       val = fetch_arg (buffer, 'd', 3);          /* Get coprocessor ID... */
  348.       if (val != 1)                /* Unusual coprocessor ID? */
  349.     fprintf_filtered (stream, "(cpid=%d) ", val);
  350.       if (place == 'i')
  351.     p += 2;                 /* Skip coprocessor extended operands */
  352.       break;
  353.  
  354.     case '*':
  355.     case '~':
  356.     case '%':
  357.     case ';':
  358.     case '@':
  359.     case '!':
  360.     case '$':
  361.     case '?':
  362.     case '/':
  363.     case '&':
  364.  
  365.       if (place == 'd')
  366.     {
  367.       val = fetch_arg (buffer, 'x', 6);
  368.       val = ((val & 7) << 3) + ((val >> 3) & 7);
  369.     }
  370.       else
  371.     val = fetch_arg (buffer, 's', 6);
  372.  
  373.       /* Get register number assuming address register.  */
  374.       regno = (val & 7) + 8;
  375.       regname = reg_names[regno];
  376.       switch (val >> 3)
  377.     {
  378.     case 0:
  379.       fprintf_filtered (stream, "%s", reg_names[val]);
  380.       break;
  381.  
  382.     case 1:
  383.       fprintf_filtered (stream, "%s", regname);
  384.       break;
  385.  
  386.     case 2:
  387.       fprintf_filtered (stream, "%s@", regname);
  388.       break;
  389.  
  390.     case 3:
  391.       fprintf_filtered (stream, "%s@+", regname);
  392.       break;
  393.  
  394.     case 4:
  395.       fprintf_filtered (stream, "%s@-", regname);
  396.       break;
  397.  
  398.     case 5:
  399.       val = NEXTWORD (p);
  400.       fprintf_filtered (stream, "%s@(%d)", regname, val);
  401.       break;
  402.   
  403.     case 6:
  404.       p = print_indexed (regno, p, addr, stream);
  405.       break;
  406.  
  407.     case 7:
  408.       switch (val & 7)
  409.         {
  410.         case 0:
  411.           val = NEXTWORD (p);
  412.           fprintf_filtered (stream, "@#");
  413.           print_address (val, stream);
  414.           break;
  415.  
  416.         case 1:
  417.           val = NEXTLONG (p);
  418.           fprintf_filtered (stream, "@#");
  419.           print_address (val, stream);
  420.           break;
  421.  
  422.         case 2:
  423.           val = NEXTWORD (p);
  424.           print_address (addr + val, stream);
  425.           break;
  426.  
  427.         case 3:
  428.           p = print_indexed (-1, p, addr, stream);
  429.           break;
  430.  
  431.         case 4:
  432.           flt_p = 1;    /* Assume it's a float... */
  433.           switch( place )
  434.           {
  435.         case 'b':
  436.           val = NEXTBYTE (p);
  437.           flt_p = 0;
  438.           break;
  439.  
  440.         case 'w':
  441.           val = NEXTWORD (p);
  442.           flt_p = 0;
  443.           break;
  444.  
  445.         case 'l':
  446.           val = NEXTLONG (p);
  447.           flt_p = 0;
  448.           break;
  449.  
  450.         case 'f':
  451.           flval = NEXTSINGLE(p);
  452.           break;
  453.  
  454.         case 'F':
  455.           flval = NEXTDOUBLE(p);
  456.           break;
  457.  
  458.         case 'x':
  459.           flval = NEXTEXTEND(p);
  460.           break;
  461.  
  462.         case 'p':
  463.           flval = NEXTPACKED(p);
  464.           break;
  465.  
  466.         default:
  467.           error ("Invalid arg format in opcode table: \"%c%c\".",
  468.                *d, place);
  469.           }
  470.           if ( flt_p )    /* Print a float? */
  471.         fprintf_filtered (stream, "#%g", flval);
  472.           else
  473.         fprintf_filtered (stream, "#%d", val);
  474.           break;
  475.  
  476.         default:
  477.           fprintf_filtered (stream, "<invalid address mode 0%o>", val);
  478.         }
  479.     }
  480.       break;
  481.  
  482.     case 'L':
  483.     case 'l':
  484.     if (place == 'w')
  485.       {
  486.         char doneany;
  487.         p1 = buffer + 2;
  488.         val = NEXTWORD (p1);
  489.         /* Move the pointer ahead if this point is farther ahead
  490.            than the last.  */
  491.         p = p1 > p ? p1 : p;
  492.         if (val == 0)
  493.           {
  494.         fputs_filtered ("#0", stream);
  495.         break;
  496.           }
  497.         if (*d == 'l')
  498.           {
  499.         register int newval = 0;
  500.         for (regno = 0; regno < 16; ++regno)
  501.           if (val & (0x8000 >> regno))
  502.             newval |= 1 << regno;
  503.         val = newval;
  504.           }
  505.         val &= 0xffff;
  506.         doneany = 0;
  507.         for (regno = 0; regno < 16; ++regno)
  508.           if (val & (1 << regno))
  509.         {
  510.           int first_regno;
  511.           if (doneany)
  512.             fputs_filtered ("/", stream);
  513.           doneany = 1;
  514.           fprintf_filtered (stream, "%s", reg_names[regno]);
  515.           first_regno = regno;
  516.           while (val & (1 << (regno + 1)))
  517.             ++regno;
  518.           if (regno > first_regno)
  519.             fprintf_filtered (stream, "-%s", reg_names[regno]);
  520.         }
  521.       }
  522.     else if (place == '3')
  523.       {
  524.         /* `fmovem' insn.  */
  525.         char doneany;
  526.         val = fetch_arg (buffer, place, 8);
  527.         if (val == 0)
  528.           {
  529.         fputs_filtered ("#0", stream);
  530.         break;
  531.           }
  532.         if (*d == 'l')
  533.           {
  534.         register int newval = 0;
  535.         for (regno = 0; regno < 8; ++regno)
  536.           if (val & (0x80 >> regno))
  537.             newval |= 1 << regno;
  538.         val = newval;
  539.           }
  540.         val &= 0xff;
  541.         doneany = 0;
  542.         for (regno = 0; regno < 8; ++regno)
  543.           if (val & (1 << regno))
  544.         {
  545.           int first_regno;
  546.           if (doneany)
  547.             fputs_filtered ("/", stream);
  548.           doneany = 1;
  549.           fprintf_filtered (stream, "fp%d", regno);
  550.           first_regno = regno;
  551.           while (val & (1 << (regno + 1)))
  552.             ++regno;
  553.           if (regno > first_regno)
  554.             fprintf_filtered (stream, "-fp%d", regno);
  555.         }
  556.       }
  557.     else
  558.       abort ();
  559.       break;
  560.  
  561.     default:
  562.       error ("Invalid arg format in opcode table: \"%c\".", *d);
  563.     }
  564.  
  565.   return (unsigned char *) p;
  566. }
  567.  
  568. /* Fetch BITS bits from a position in the instruction specified by CODE.
  569.    CODE is a "place to put an argument", or 'x' for a destination
  570.    that is a general address (mode and register).
  571.    BUFFER contains the instruction.  */
  572.  
  573. static int
  574. fetch_arg (buffer, code, bits)
  575.      unsigned char *buffer;
  576.      char code;
  577.      int bits;
  578. {
  579.   register int val;
  580.   switch (code)
  581.     {
  582.     case 's':
  583.       val = buffer[1];
  584.       break;
  585.  
  586.     case 'd':            /* Destination, for register or quick.  */
  587.       val = (buffer[0] << 8) + buffer[1];
  588.       val >>= 9;
  589.       break;
  590.  
  591.     case 'x':            /* Destination, for general arg */
  592.       val = (buffer[0] << 8) + buffer[1];
  593.       val >>= 6;
  594.       break;
  595.  
  596.     case 'k':
  597.       val = (buffer[3] >> 4);
  598.       break;
  599.  
  600.     case 'C':
  601.       val = buffer[3];
  602.       break;
  603.  
  604.     case '1':
  605.       val = (buffer[2] << 8) + buffer[3];
  606.       val >>= 12;
  607.       break;
  608.  
  609.     case '2':
  610.       val = (buffer[2] << 8) + buffer[3];
  611.       val >>= 6;
  612.       break;
  613.  
  614.     case '3':
  615.     case 'j':
  616.       val = (buffer[2] << 8) + buffer[3];
  617.       break;
  618.  
  619.     case '4':
  620.       val = (buffer[4] << 8) + buffer[5];
  621.       val >>= 12;
  622.       break;
  623.  
  624.     case '5':
  625.       val = (buffer[4] << 8) + buffer[5];
  626.       val >>= 6;
  627.       break;
  628.  
  629.     case '6':
  630.       val = (buffer[4] << 8) + buffer[5];
  631.       break;
  632.  
  633.     case '7':
  634.       val = (buffer[2] << 8) + buffer[3];
  635.       val >>= 7;
  636.       break;
  637.       
  638.     case '8':
  639.       val = (buffer[2] << 8) + buffer[3];
  640.       val >>= 10;
  641.       break;
  642.  
  643.     default:
  644.       abort ();
  645.     }
  646.  
  647.   switch (bits)
  648.     {
  649.     case 3:
  650.       return val & 7;
  651.     case 4:
  652.       return val & 017;
  653.     case 5:
  654.       return val & 037;
  655.     case 6:
  656.       return val & 077;
  657.     case 7:
  658.       return val & 0177;
  659.     case 8:
  660.       return val & 0377;
  661.     case 12:
  662.       return val & 07777;
  663.     default:
  664.       abort ();
  665.     }
  666. }
  667.  
  668. /* Print an indexed argument.  The base register is BASEREG (-1 for pc).
  669.    P points to extension word, in buffer.
  670.    ADDR is the nominal core address of that extension word.  */
  671.  
  672. static unsigned char *
  673. print_indexed (basereg, p, addr, stream)
  674.      int basereg;
  675.      unsigned char *p;
  676.      FILE *stream;
  677.      CORE_ADDR addr;
  678. {
  679.   register int word;
  680.   static char *scales[] = {"", "*2", "*4", "*8"};
  681.   register int base_disp;
  682.   register int outer_disp;
  683.   char buf[40];
  684.  
  685.   word = NEXTWORD (p);
  686.  
  687.   /* Generate the text for the index register.
  688.      Where this will be output is not yet determined.  */
  689.   printf_filtered (buf, "[%s.%c%s]",
  690.        reg_names[(word >> 12) & 0xf],
  691.        (word & 0x800) ? 'l' : 'w',
  692.        scales[(word >> 9) & 3]);
  693.  
  694.   /* Handle the 68000 style of indexing.  */
  695.  
  696.   if ((word & 0x100) == 0)
  697.     {
  698.       print_base (basereg,
  699.           ((word & 0x80) ? word | 0xff00 : word & 0xff)
  700.           + ((basereg == -1) ? addr : 0),
  701.           stream);
  702.       fputs_filtered (buf, stream);
  703.       return p;
  704.     }
  705.  
  706.   /* Handle the generalized kind.  */
  707.   /* First, compute the displacement to add to the base register.  */
  708.  
  709.   if (word & 0200)
  710.     basereg = -2;
  711.   if (word & 0100)
  712.     buf[0] = 0;
  713.   base_disp = 0;
  714.   switch ((word >> 4) & 3)
  715.     {
  716.     case 2:
  717.       base_disp = NEXTWORD (p);
  718.       break;
  719.     case 3:
  720.       base_disp = NEXTLONG (p);
  721.     }
  722.   if (basereg == -1)
  723.     base_disp += addr;
  724.  
  725.   /* Handle single-level case (not indirect) */
  726.  
  727.   if ((word & 7) == 0)
  728.     {
  729.       print_base (basereg, base_disp, stream);
  730.       fputs_filtered (buf, stream);
  731.       return p;
  732.     }
  733.  
  734.   /* Two level.  Compute displacement to add after indirection.  */
  735.  
  736.   outer_disp = 0;
  737.   switch (word & 3)
  738.     {
  739.     case 2:
  740.       outer_disp = NEXTWORD (p);
  741.       break;
  742.     case 3:
  743.       outer_disp = NEXTLONG (p);
  744.     }
  745.  
  746.   fprintf_filtered (stream, "%d(", outer_disp);
  747.   print_base (basereg, base_disp, stream);
  748.  
  749.   /* If postindexed, print the closeparen before the index.  */
  750.   if (word & 4)
  751.     fprintf_filtered (stream, ")%s", buf);
  752.   /* If preindexed, print the closeparen after the index.  */
  753.   else
  754.     fprintf_filtered (stream, "%s)", buf);
  755.  
  756.   return p;
  757. }
  758.  
  759. /* Print a base register REGNO and displacement DISP, on STREAM.
  760.    REGNO = -1 for pc, -2 for none (suppressed).  */
  761.  
  762. static void
  763. print_base (regno, disp, stream)
  764.      int regno;
  765.      int disp;
  766.      FILE *stream;
  767. {
  768.   if (regno == -2)
  769.     fprintf_filtered (stream, "%d", disp);
  770.   else if (regno == -1)
  771.     fprintf_filtered (stream, "0x%x", disp);
  772.   else
  773.     fprintf_filtered (stream, "%d(%s)", disp, reg_names[regno]);
  774. }
  775.  
  776. #ifdef _M68881
  777. static int have_fpu = 1;
  778. #else
  779. static int have_fpu = 0;
  780. #endif
  781. /* This is not part of insn printing, but it is machine-specific,
  782.    so this is a convenient place to put it.
  783.  
  784.    Convert a 68881 extended float to a double.
  785.    FROM is the address of the extended float.
  786.    Store the double in *TO.  */
  787.  
  788. convert_from_68881 (from, to)
  789.      char *from;
  790.      double *to;
  791. {
  792.   if (!have_fpu)
  793.     {
  794.       *to = 0.0;
  795.       return;
  796.     }
  797.   else
  798.     {
  799. #ifdef HPUX_ASM
  800.       asm volatile ("mov.l 8(%a6),%a0");
  801.       asm volatile ("mov.l 12(%a6),%a1");
  802.       asm volatile ("fmove.x (%a0),%fp0");
  803.       asm volatile ("fmove.d %fp0,(%a1)");
  804. #else /* not HPUX_ASM */
  805. #if 0
  806.       asm volatile ("movl a6@(8),a0");
  807.       asm volatile ("movl a6@(12),a1");
  808.       asm volatile ("fmovex a0@,fp0");
  809.       asm volatile ("fmoved fp0,a1@");
  810. #else
  811.       /* Hand-assemble those insns since some assemblers lose
  812.      and some have different syntax.  */
  813.       asm volatile (".word 020156");
  814.       asm volatile (".word 8");
  815.       asm volatile (".word 021156");
  816.       asm volatile (".word 12");
  817.       asm volatile (".long 0xf2104800");
  818.       asm volatile (".long 0xf2117400");
  819. #endif
  820. #endif /* not HPUX_ASM */
  821.     }
  822. }
  823.  
  824. /* The converse: convert the double *FROM to an extended float
  825.    and store where TO points.  */
  826.  
  827. convert_to_68881 (from, to)
  828.      double *from;
  829.      char *to;
  830. {
  831.   if (!have_fpu)
  832.       return;
  833.   else
  834.     {
  835. #ifdef HPUX_ASM
  836.       asm volatile ("mov.l 8(%a6),%a0");
  837.       asm volatile ("mov.l 12(%a6),%a1");
  838.       asm volatile ("fmove.d (%a0),%fp0");
  839.       asm volatile ("fmove.x %fp0,(%a1)");
  840. #else /* not HPUX_ASM */
  841. #if 0
  842.       asm volatile ("movl a6@(8),a0");
  843.       asm volatile ("movl a6@(12),a1");
  844.       asm volatile ("fmoved a0@,fp0");
  845.       asm volatile ("fmovex fp0,a1@");
  846. #else
  847.       /* Hand-assemble those insns since some assemblers lose.  */
  848.       asm volatile (".word 020156");
  849.       asm volatile (".word 8");
  850.       asm volatile (".word 021156");
  851.       asm volatile (".word 12");
  852.       asm volatile (".long 0xf2105400");
  853.       asm volatile (".long 0xf2116800");
  854. #endif
  855. #endif /* not HPUX_ASM */
  856.     }
  857. }
  858.